package com.cloudcc.mobile.weight;

import android.content.Context;
import android.content.res.ColorStateList;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.graphics.Typeface;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.text.Editable;
import android.text.Spannable;
import android.text.Spanned;
import android.text.style.ClickableSpan;
import android.text.style.ImageSpan;
import android.text.style.StyleSpan;
import android.text.style.TextAppearanceSpan;
import android.text.style.UnderlineSpan;
import android.util.AttributeSet;
import android.view.View;
import android.widget.EditText;

public class RichEditText extends EditText {
	int size = 18;
	int color = Color.BLACK;
	private String mark = "[img] ";
	private OnImageClickListener onClick;
	private OnSelectionChanged onSelectionChanged;
	private Context mContext;

	public RichEditText(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
		mContext = context;
		// TODO Auto-generated constructor stub
	}

	public RichEditText(Context context, AttributeSet attrs) {
		super(context, attrs);
		mContext = context;
	}

	public RichEditText(Context context) {
		super(context);
		mContext = context;
	}

	// 加粗
	public void enabledBlod(boolean enabled) {
		Spannable sp = getEditableText();
		if (enabled) {
			sp.setSpan(new StyleSpan(Typeface.BOLD), getSelectionStart(),
					getSelectionEnd(), Spanned.SPAN_MARK_POINT);
		} else {
			int prologueStart = Integer.MAX_VALUE;
			int epilogueEnd = -1;
			StyleSpan[] spans = sp.getSpans(getSelectionStart(),
					getSelectionEnd(), StyleSpan.class);
			for (StyleSpan span : spans) {
				if (span.getStyle() == Typeface.BOLD) {
					int spanStart = sp.getSpanStart(span);
					if (spanStart < getSelectionStart()) {
						prologueStart = Math.min(prologueStart, spanStart);
					}
					int spanEnd = sp.getSpanEnd(span);

					if (spanEnd > getSelectionEnd()) {
						epilogueEnd = Math.max(epilogueEnd, spanEnd);
					}
					sp.removeSpan(span);
				}
			}
			if (prologueStart < Integer.MAX_VALUE) {
				sp.setSpan(new StyleSpan(Typeface.BOLD), prologueStart,
						getSelectionStart(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
			}
			if (epilogueEnd > -1) {
				sp.setSpan(new StyleSpan(Typeface.BOLD), getSelectionEnd(),
						epilogueEnd, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
			}
		}
	}

	// 斜体
	public void enabledItalic(boolean enabled) {
		Spannable sp = getEditableText();
		if (enabled) {
			sp.setSpan(new StyleSpan(Typeface.ITALIC), getSelectionStart(),
					getSelectionEnd(), Spanned.SPAN_MARK_POINT);
		} else {
			int prologueStart = Integer.MAX_VALUE;
			int epilogueEnd = -1;
			StyleSpan[] spans = sp.getSpans(getSelectionStart(),
					getSelectionEnd(), StyleSpan.class);
			for (StyleSpan span : spans) {
				if (span.getStyle() == Typeface.ITALIC) {
					int spanStart = sp.getSpanStart(span);
					if (spanStart < getSelectionStart()) {
						prologueStart = Math.min(prologueStart, spanStart);
					}
					int spanEnd = sp.getSpanEnd(span);

					if (spanEnd > getSelectionEnd()) {
						epilogueEnd = Math.max(epilogueEnd, spanEnd);
					}
					sp.removeSpan(span);
				}
			}
			if (prologueStart < Integer.MAX_VALUE) {
				sp.setSpan(new StyleSpan(Typeface.ITALIC), prologueStart,
						getSelectionStart(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
			}
			if (epilogueEnd > -1) {
				sp.setSpan(new StyleSpan(Typeface.ITALIC), getSelectionEnd(),
						epilogueEnd, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
			}
		}
	}

	// 下划线
	public void enabledUnderline(boolean enabled) {
		Spannable sp = getEditableText();
		if (enabled) {
			sp.setSpan(new UnderlineSpan(), getSelectionStart(),
					getSelectionEnd(), Spanned.SPAN_MARK_POINT);
		} else {
			int prologueStart = Integer.MAX_VALUE;
			int epilogueEnd = -1;
			UnderlineSpan[] spans = sp.getSpans(getSelectionStart(),
					getSelectionEnd(), UnderlineSpan.class);
			for (UnderlineSpan span : spans) {
				int spanStart = sp.getSpanStart(span);
				if (spanStart < getSelectionStart()) {
					prologueStart = Math.min(prologueStart, spanStart);
				}
				int spanEnd = sp.getSpanEnd(span);

				if (spanEnd > getSelectionEnd()) {
					epilogueEnd = Math.max(epilogueEnd, spanEnd);
				}
				sp.removeSpan(span);
			}
			if (prologueStart < Integer.MAX_VALUE) {
				sp.setSpan(new UnderlineSpan(), prologueStart,
						getSelectionStart(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
			}
			if (epilogueEnd > -1) {
				sp.setSpan(new UnderlineSpan(), getSelectionEnd(), epilogueEnd,
						Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
			}
		}
	}

	public boolean blodInSelection() {
		Spannable sp = getEditableText();
		StyleSpan[] spans = sp.getSpans(getSelectionStart(),
				getSelectionStart(), StyleSpan.class);
		for (StyleSpan span : spans) {
			if (span.getStyle() == Typeface.BOLD) {
				return true;
			}
		}
		return false;
	}

	public boolean italicInSelection() {
		Spannable sp = getEditableText();
		StyleSpan[] spans = sp.getSpans(getSelectionStart(),
				getSelectionStart(), StyleSpan.class);
		for (StyleSpan span : spans) {
			if (span.getStyle() == Typeface.ITALIC) {
				return true;
			}
		}
		return false;
	}

	public boolean underLineInSelection() {
		Spannable sp = getEditableText();
		return sp.getSpans(getSelectionStart(), getSelectionEnd(),
				UnderlineSpan.class).length > 0;
	}

	@Override
	protected void onSelectionChanged(int selStart, int selEnd) {
		if (onSelectionChanged != null) {
			onSelectionChanged.onChanged(blodInSelection(),
					italicInSelection(), underLineInSelection());
		}
		super.onSelectionChanged(selStart, selEnd);
	}

	public void setOnSelectionChanged(OnSelectionChanged onSelectionChanged) {
		this.onSelectionChanged = onSelectionChanged;
	}

	// 字体颜色和大小
	public void setCurrentText(int color, int size) {
		Spannable sp = getEditableText();
		if (getSelectionStart() == getSelectionEnd()) {
			if (color == this.color && size == this.size) {
				return;
			} else {
				int prologueStart = Integer.MAX_VALUE;
				int epilogueEnd = -1;
				TextAppearanceSpan[] spans = sp.getSpans(getSelectionStart(),
						getSelectionEnd(), TextAppearanceSpan.class);
				for (TextAppearanceSpan span : spans) {
					if (span.getTextSize() == this.size
							&& span.getTextColor().getDefaultColor() == this.color) {
						int spanStart = sp.getSpanStart(span);
						if (spanStart < getSelectionStart()) {
							prologueStart = Math.min(prologueStart, spanStart);
						}
						int spanEnd = sp.getSpanEnd(span);

						if (spanEnd > getSelectionEnd()) {
							epilogueEnd = Math.max(epilogueEnd, spanEnd);
						}
						sp.removeSpan(span);
					}
				}
				if (prologueStart < Integer.MAX_VALUE) {
					sp.setSpan(new TextAppearanceSpan(null, 0, this.size,
							new ColorStateList(new int[][] { { 0 } },
									new int[] { this.color }), null),
							prologueStart, getSelectionStart(),
							Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
				}
				if (epilogueEnd > -1) {
					sp.setSpan(new TextAppearanceSpan(null, 0, this.size,
							new ColorStateList(new int[][] { { 0 } },
									new int[] { this.color }), null),
							getSelectionEnd(), epilogueEnd,
							Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
				}
			}
			sp.setSpan(new TextAppearanceSpan(null, 0, size,
					new ColorStateList(new int[][] { { 0 } },
							new int[] { color }), null), getSelectionStart(),
					getSelectionEnd(), Spannable.SPAN_MARK_POINT);
		} else {
			int prologueStart = -1;
			int epilogueEnd = Integer.MAX_VALUE;
			TextAppearanceSpan[] spans = sp.getSpans(getSelectionStart(),
					getSelectionEnd(), TextAppearanceSpan.class);
			for (TextAppearanceSpan span : spans) {
				if (span.getTextSize() == size
						&& span.getTextColor().getDefaultColor() == color) {
					int spanStart = sp.getSpanStart(span);
					if (spanStart < getSelectionStart()) {
						prologueStart = Math.max(prologueStart, spanStart);
					}
					int spanEnd = sp.getSpanEnd(span);

					if (spanEnd > getSelectionEnd()) {
						epilogueEnd = Math.min(epilogueEnd, spanEnd);
					}
					sp.removeSpan(span);
				}
			}
			if (prologueStart > -1) {
				sp.setSpan(new TextAppearanceSpan(null, 0, size,
						new ColorStateList(new int[][] { { 0 } },
								new int[] { color }), null), prologueStart,
						getSelectionStart(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
			}
			if (epilogueEnd < Integer.MAX_VALUE) {
				sp.setSpan(new TextAppearanceSpan(null, 0, size,
						new ColorStateList(new int[][] { { 0 } },
								new int[] { color }), null), getSelectionEnd(),
						epilogueEnd, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
			}
			sp.setSpan(new TextAppearanceSpan(null, 0, size,
					new ColorStateList(new int[][] { { 0 } },
							new int[] { color }), null),
					prologueStart > -1 ? prologueStart : getSelectionStart(),
					epilogueEnd < Integer.MAX_VALUE ? epilogueEnd
							: getSelectionEnd(), Spannable.SPAN_MARK_POINT);
		}
		this.color = color;
		this.size = size;
	}

	public int getCurrentSize() {
		return size;
	}

	public int getCurrentColor() {
		return color;
	}

	public void addImage(final String path) {
		Spannable sp = getEditableText();
		int start = getSelectionStart();
		int end = getSelectionEnd();
		((Editable) sp).insert(getSelectionStart(), mark);
		Drawable drawable = compressImage(path);
		int width = drawable.getIntrinsicWidth();
		int height = drawable.getIntrinsicHeight();
		if (width > 600) {
			float change;
			change = 600f / width;
			height = (int) (height * change);
			width = 600;
		}
		drawable.setBounds(0, 0, width, height);
		sp.setSpan(new ImageSpan(drawable, path, ImageSpan.ALIGN_BASELINE),
				start, end + mark.length() - 1,
				Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);

		ClickableSpan click_span = new ClickableSpan() {
			@Override
			public void onClick(View widget) {
				if (onClick != null) {
					onClick.onImageClick(widget, path);
				}
			}
		};

		ClickableSpan[] click_spans = sp.getSpans(start, end + mark.length()
				- 1, ClickableSpan.class);
		if (click_spans.length != 0) {
			for (ClickableSpan c_span : click_spans) {
				sp.removeSpan(c_span);
			}
		}

		sp.setSpan(click_span, start, end + mark.length() - 1,
				Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);

		((Editable) sp).delete(end + mark.length() - 1, end + mark.length());
	}

	public Drawable compressImage(String source) {
		BitmapFactory.Options bmpFactoryOptions = new BitmapFactory.Options();
		bmpFactoryOptions.inJustDecodeBounds = true;
		Bitmap bmp = BitmapFactory.decodeFile(source, bmpFactoryOptions);
		int heightRatio = (int) Math
				.ceil(bmpFactoryOptions.outHeight
						/ (float) mContext.getResources().getDisplayMetrics().heightPixels);
		int widthRatio = (int) Math
				.ceil(bmpFactoryOptions.outWidth
						/ (float) mContext.getResources().getDisplayMetrics().widthPixels);
		if (heightRatio > 1 && widthRatio > 1) {
			if (heightRatio > widthRatio) {
				bmpFactoryOptions.inSampleSize = heightRatio;
			} else {
				bmpFactoryOptions.inSampleSize = widthRatio;
			}
		}
		bmpFactoryOptions.inJustDecodeBounds = false;
		bmp = BitmapFactory.decodeFile(source, bmpFactoryOptions);
		Drawable drawable = new BitmapDrawable(mContext.getResources(), bmp);
		int width = drawable.getIntrinsicWidth();
		int height = drawable.getIntrinsicHeight();
		if (width > 600) {
			float change;
			change = 600f / width;
			height = (int) (height * change);
			width = 600;
		}
		drawable.setBounds(0, 0, width, height);
		return drawable;
	}

	public void setOnImageClickListener(OnImageClickListener onImageClick) {
		onClick = onImageClick;

	}

	public interface OnSelectionChanged {
		public void onChanged(boolean inBlod, boolean inItalic,
                              boolean inUnderline);
	}

	public interface OnImageClickListener {
		public void onImageClick(View v, String src);
	}
}
